package helpers;

import aggregator.EsperAggregator;
import com.wolfram.jlink.KernelLink;
import com.wolfram.jlink.MathLinkException;
import com.wolfram.jlink.MathLinkFactory;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

public class MathLink {

	private static MathLink linkInstance = new MathLink();
	
	private KernelLink ml = null;
	
	
	
	private MathLink(){
	    try {
	    	ml = MathLinkFactory.createKernelLink("-linkmode launch -linkname 'c:\\program files\\wolfram research\\mathematica\\9.0\\mathkernel'");
	    } catch (Exception e) {
	        System.out.println("Fatal error opening link: " 
	                        + e.getMessage());
	        return;
	    }
	    try {
	        // Get rid of the initial InputNamePacket the kernel will send
	        // when it is launched.
	        ml.discardAnswer();
	
	        //ml.evaluate("Get[\"C:\\Users\\Linar\\Documents\\user\\functions.m\"]");
	        //ml.discardAnswer();


            ml.evaluate("EstimateLocation[data_] := (source = {0, 0}; source1 = {24, 0}; source2 = {12.6, 16.2}; source3 = {11.4, 4.8}; "+
                    "fit = NonlinearModelFit[data, Norm[{x, y} - {x0, y0}], {x0, y0}, {x, y}(*, "+
                    "Weights -> 1/data[[All,3]]^2*)]; ellipsoid = "+
                    "fit[\"ParameterConfidenceRegion\", ConfidenceLevel -> 0.95]; "+
                    "solution = fit[\"ParameterConfidenceIntervalTableEntries\"][[All,1]];"+
                    "graphic = Graphics[{Opacity[0.2], EdgeForm[Opacity[0.75]], White, "+
                    "(Disk[Most[#1], Last[#1]] & ) /@ data, Opacity[1], Red, ellipsoid,"+
                    "PointSize[0.0125], Blue, Point[source], Green, Point[source1], Yellow, Point[source2], Gray, Point[source3], Red, Point[solution], "+
                    "PointSize[0.0083], White, (Point[Most[#1]] & ) /@ data},"+
                    "Background -> Black, ImageSize -> 600]; Return[solution]; )");

//	        ml.evaluate("EstimateLocation[data_] := (source = {0, 0}; "+
//	        "fit = NonlinearModelFit[data, Norm[{x, y} - {x0, y0}], {x0, y0}, {x, y}, "+
//	          "Weights -> 1/data[[All,3]]^2]; (*ellipsoid = "+
//	         "fit[\"ParameterConfidenceRegion\", ConfidenceLevel -> 0.95]; *)"+
//	        "solution = fit[\"ParameterConfidenceIntervalTableEntries\"][[All,1]];"+
//	        "(*Graphics[{Opacity[0.2], EdgeForm[Opacity[0.75]], White, "+
//	          "(Disk[Most[#1], Last[#1]] & ) /@ data, Opacity[1], Red, ellipsoid,"+
//	          "PointSize[0.0125], Blue, Point[source], Red, Point[solution], "+
//	          "PointSize[0.0083], White, (Point[Most[#1]] & ) /@ data},"+
//	         "Background -> Black, ImageSize -> 600];*) Return[solution]; )");
	        
	        ml.discardAnswer();
	

	
	        // {{-1.91373, -0.799904, 2.04001}, {-0.935453, -0.493735, 0.959304}, {0.630964, -0.653075, 0.728477}, {0.310857, -0.018258, 0.301885}, {0.0431084, 1.25321, 1.19012}}
	        
	        //ml.waitForAnswer();
	        //Object result = ml.getString();
	        
	        
	
	    } catch (Exception e) {
	        System.out.println("MathLinkException occurred: "
	                        + e.getMessage());
	    }
	}


	public void EstimateLocation(ConcurrentHashMap<String,String> readers, String tag){
		Object[] distances = readers.values().toArray(); 
		
        try {
            String distanceString = "EstimateLocation[{{"+distances[0]+"}";

            for (int i=1 ; i<distances.length ; i++){
               distanceString += ",{"+distances[i]+"}";
            }


			ml.evaluate(distanceString+ "}]");
			
			ml.waitForAnswer();
	        
	        float[] result = ml.getFloatArray1();

            HashMap<String, Object>  locationEvent = new HashMap<>();

            locationEvent.put("tag", tag);
            locationEvent.put("x", ((Float)(result[0] * 100f)).intValue());
            locationEvent.put("y", ((Float)(result[1] * 100f)).intValue());

            EsperAggregator.engine.getEPRuntime().sendEvent(locationEvent,"TagLocation");

	        //System.out.println(result[0]+", " + result[1]);
		} catch (MathLinkException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
        
	}

    public ByteArrayInputStream getVisualiazedData(){
        try {

            return new ByteArrayInputStream(ml.evaluateToImage("graphic", 0, 0));
//            return ImageIO.read(new ByteArrayInputStream(ml.evaluateToImage("graphic", 0, 0)));
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            return null;
        }
    }

	public static MathLink getLinkInstance() {

		return linkInstance;
	}


}
